package com.huanong.it.xwadmin.authority.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.huanong.it.xwadmin.authority.common.entity.MyConst;
import com.huanong.it.xwadmin.authority.common.entity.SimpleGrantedAuthority;
import com.huanong.it.xwadmin.authority.common.utils.RedisUtil;

import com.huanong.it.xwadmin.authority.domain.*;
import com.huanong.it.xwadmin.authority.mapper.*;
import com.huanong.it.xwadmin.authority.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;

import java.util.*;

/**
* @author Limhuang
* @description 针对表【sys_user】的数据库操作Service实现
* @createDate 2024-06-23 22:12:37
*/
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User>
    implements UserService{
    @Autowired
    private UserMapper userMapper;

    @Autowired
    private MenuMapper menuMapper;

    @Autowired
    private RoleMenuMapper roleMenuMapper;

    @Autowired
    private RoleMapper roleMapper;

    @Autowired
    private UserRoleMapper userRoleMapper;

    @Autowired
    private BCryptPasswordEncoder bCryptPasswordEncoder;

    @Autowired
    private RedisUtil redisUtil;
    @Value("${jwt.expiration}")
    private Integer expireTime;
    @Override
    public User getUserByUserName(String username) {
        List<User> users = userMapper.selectList(new QueryWrapper<User>().lambda().eq(User::getUsername, username));
        if(users.size()>0){
            User user = users.get(0);
            user.setRoles(getRoles(username));
            user.setMenus(getMenus(username));
            user.setAuthorities(getAuthorities(user.getId()));
            return users.get(0);
        }
        return null;
    }

    @Override
    public User register(User user) {
        List<User> users = userMapper.selectList(new QueryWrapper<User>().lambda().eq(User::getUsername, user.getUsername()));
        if(users!=null&&users.size()>0){
            throw new RuntimeException("用户已存在");
        }
        user.setCreated(new Date());
        user.setUpdated(new Date());
        String password = user.getPassword();
        password= bCryptPasswordEncoder.encode(password);
        user.setPassword(password);
        userMapper.insert(user);
        addRole(user.getId(),3L);
        return user;
    }

    @Override
    public Set<GrantedAuthority> getAuthorities(Long userId) {
        String username=userMapper.selectById(userId).getUsername();
        String key = username+ MyConst.AUTHENTICATION;
        if(redisUtil.hasKey(key)){
            return (Set<GrantedAuthority>) redisUtil.get(key);
        }
        QueryWrapper<UserRole> queryWrapper = new QueryWrapper();
        queryWrapper.lambda().eq(UserRole::getUserId,userId);
        List<UserRole> userRoles = userRoleMapper.selectList(queryWrapper);
        List<Long> roleIds = new ArrayList<>();
        userRoles.stream().forEach(userRole -> {
            roleIds.add(userRole.getRoleId());
        });

        if(roleIds.size()==0){
            return new HashSet<>();
        }
        List<Role> roles= roleMapper.selectBatchIds(roleIds);

        List<RoleMenu> roleMenus = new ArrayList<>();
        QueryWrapper<RoleMenu> roleMenuQueryWrapper = new QueryWrapper<>();
        roleMenuQueryWrapper.lambda().in(RoleMenu::getRoleId,roleIds);
        roleMenus = roleMenuMapper.selectList(roleMenuQueryWrapper);

        List<Long> menuIds = new ArrayList<>();
        roleMenus.stream().forEach(roleMenu -> {
            menuIds.add(roleMenu.getMenuId());
        });
        List<Menu> menus = menuMapper.selectBatchIds(menuIds);

        if(menus.size()==0&&roles.size()==0){
            return new HashSet<>();
        }
        Set<GrantedAuthority> grantedAuthorities = new HashSet<>();
        for (int i = 0; i < menus.size(); i++) {
            SimpleGrantedAuthority simpleGrantedAuthority = new SimpleGrantedAuthority(menus.get(i).getPerms());
            grantedAuthorities.add(simpleGrantedAuthority);
        }
        for (int i = 0; i < roles.size(); i++) {
            SimpleGrantedAuthority simpleGrantedAuthority = new SimpleGrantedAuthority("ROLE_"+roles.get(i).getCode());
            grantedAuthorities.add(simpleGrantedAuthority);
        }


        redisUtil.set(key,grantedAuthorities,60*expireTime);
        return (Set<GrantedAuthority>) redisUtil.get(key);
    }

    @Override
    public Set<Role> getRoles(String username) {
        String key = username+ MyConst.ROLE;
        if(redisUtil.hasKey(key)){
            return (Set<Role>) redisUtil.get(key);
        }
        Set<Role> roles = new HashSet<>();
        List<User> users = userMapper.selectList(new QueryWrapper<User>().lambda().eq(User::getUsername, username));
        if(users.size()>0){
            User user = users.get(0);
            QueryWrapper<UserRole> queryWrapper = new QueryWrapper();
            queryWrapper.lambda().eq(UserRole::getUserId,user.getId());
            List<UserRole> userRoles = userRoleMapper.selectList(queryWrapper);
            List<Long> roleIds = new ArrayList<>();
            userRoles.stream().forEach(userRole -> {
                roleIds.add(userRole.getRoleId());
            });
            if(roleIds.size()>0){
                roles = new HashSet<>(roleMapper.selectBatchIds(roleIds));
            }
        }
        redisUtil.set(key,roles,60*expireTime);
        return (Set<Role>) redisUtil.get(key);
    }

    @Override
    public List<Menu> getMenus(String username) {
        String key = username+ MyConst.MENU;
        if(redisUtil.hasKey(key)){
            return (List<Menu>) redisUtil.get(key);
        }
        List<Menu> menus = new ArrayList<>();
        Set<Role> roles = getRoles(username);
        List<Long> roleIds = new ArrayList<>();
        roles.stream().forEach(role -> {
            roleIds.add(role.getId());
        });
        if(roleIds.size()>0){
            List<RoleMenu> roleMenus;
            QueryWrapper<RoleMenu> roleMenuQueryWrapper = new QueryWrapper<>();
            roleMenuQueryWrapper.lambda().in(RoleMenu::getRoleId,roleIds);
            roleMenus = roleMenuMapper.selectList(roleMenuQueryWrapper);

            List<Long> menuIds = new ArrayList<>();
            roleMenus.stream().forEach(roleMenu -> {
                menuIds.add(roleMenu.getMenuId());
            });
            if(menuIds.size()>0){
                menus = menuMapper.selectBatchIds(menuIds);
            }
        }
        redisUtil.set(key,menus,60*expireTime);
        return (List<Menu>) redisUtil.get(key);
    }

    @Override
    public User addRole(Long userId, Long roleId) {
        UserRole userRole = new UserRole(null,userId,roleId);
        userRoleMapper.insert(userRole);
        return null;
    }

    @Override
    public User addRoles(Long userId, List<Long> roleIds) {
        for (Long roleId:
             roleIds) {
            userRoleMapper.insert(new UserRole(null,userId,roleId));
        }
        return null;
    }

    @Override
    public User removeRole(Long userId, Long roleId) {
           userRoleMapper.delete(new QueryWrapper<UserRole>().lambda().eq(UserRole::getUserId,userId).eq(UserRole::getRoleId,roleId));
        return null;
    }

    @Override
    public User removeRoles(Long userId, List<Long> roleIds) {
        for (Long roleId:
                roleIds) {
            userRoleMapper.delete(new QueryWrapper<UserRole>().lambda().eq(UserRole::getUserId,userId).eq(UserRole::getRoleId,roleId));
        }
        return null;
    }

    @Override
    public User updateRoles(Long userId, List<Long> roleIds) {
        userRoleMapper.delete(new QueryWrapper<UserRole>().lambda().eq(UserRole::getUserId,userId));
        addRoles(userId,roleIds);
        return null;
    }


}




